home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 June: Reference Library / Dev.CD Jun 99 RL Disk 1.toast / Technical Documentation / Develop / develop Issue 28 / develop Issue 28 code / CurveLayout / AccurateShapesLibrary / ShapeMeasurement.c < prev   
Encoding:
C/C++ Source or Header  |  1996-10-01  |  9.9 KB  |  416 lines  |  [TEXT/CWIE]

  1. /**********************************************************
  2.  
  3.  
  4.     File: ShapeMeasurement.c
  5.     
  6.     This file contains utilities that can more accurately measure
  7.     shapes than the functions built into QuickDraw GX.  While the
  8.     functions in GX are accurate enough for doing normal dashing of
  9.     shapes, the slight errors are visually obvious when using them
  10.     for text positioning. 
  11.     
  12.     Much thanks to Joseph Maurer for implementing the hard-core
  13.     math part of this.
  14.  
  15. ************************************************************/
  16.  
  17.  
  18.  
  19.  
  20. #include "Types.h"
  21. #include "GXTypes.h"
  22. #include "GXMath.h"
  23. #include "GXGraphics.h"
  24. #include "GXLayout.h"
  25. #include "GXExceptions.h"
  26.  
  27. #include "ComputeLength.h"
  28.  
  29. #include "PathWalking.h"
  30. #include "AccurateShapes.h"
  31.  
  32.  
  33. /****
  34.     Structure for state required
  35.     when computing ShapeLengthToPoint
  36. ****/
  37.  
  38. typedef struct {
  39.  
  40.     gxPoint        currentPoint;                            // the current point in our state.
  41.     gxPoint        firstPoint;                                // the first point in the current contour.
  42.     long            currentContour;                        // the contour we are currently looking at.
  43.     long            desiredContour;                        // the contour we are interested in. (zero means all contours)
  44.     double        desiredLength;                        // the length we are after.
  45.     double        currentLength;                        // cache of current length;
  46.  
  47.     gxPoint        location;                                    // we'll put the position we find here.
  48.     gxPoint        tangent;                                    // the tangent point will end up here.
  49.     
  50. } TShapeLenRec;
  51.  
  52.  
  53. /* Callback routines for ShapeLengthToPoint */
  54.  
  55.  
  56.  
  57. Boolean    ShapeLenToPtMoveto(gxPoint *p, TShapeLenRec* pWalk);
  58. Boolean    ShapeLenToPtMoveto(gxPoint *p, TShapeLenRec* pWalk)
  59.     {
  60.  
  61.         pWalk->currentPoint.x = p->x;
  62.         pWalk->currentPoint.y = p->y;
  63.         pWalk->firstPoint.x = p->x;
  64.         pWalk->firstPoint.y = p->y;
  65.  
  66.         pWalk->currentContour += 1;
  67.  
  68.         /* if we've passed the desired contour, stop early */
  69.                 
  70.         if ( (pWalk->desiredContour != 0 ) && (pWalk->currentContour > pWalk->desiredContour) )
  71.             return(true);
  72.         else                
  73.             return(false);
  74.     }
  75.  
  76.  
  77.  
  78. Boolean    ShapeLenToPtLineto(gxPoint *p, TShapeLenRec* pWalk);
  79. Boolean    ShapeLenToPtLineto(gxPoint *p, TShapeLenRec* pWalk)
  80.     {
  81.         gxLine            aLine;
  82.         Boolean            stop = false;
  83.         double            segmentLength;
  84.  
  85.  
  86.         aLine.first.x = pWalk->currentPoint.x;
  87.         aLine.first.y = pWalk->currentPoint.y;
  88.         aLine.last.x = p->x;
  89.         aLine.last.y = p->y;
  90.         
  91.         pWalk->currentPoint.x = p->x;
  92.         pWalk->currentPoint.y = p->y;
  93.         
  94.         if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour)  ) {
  95.         
  96.             segmentLength = GetLineLength(&aLine);
  97.             
  98.             /* if we've exceeded the desired length, then we're on the correct segment */
  99.             
  100.             if (pWalk->currentLength + segmentLength >= pWalk->desiredLength) {
  101.             
  102.                 /* find the point on this segment that is the length we want */
  103.                 
  104.                 LineLengthToPoint(pWalk->desiredLength - pWalk->currentLength, &aLine, &(pWalk->location), &(pWalk->tangent) );
  105.  
  106.                 stop = true;
  107.             
  108.             }//end if
  109.         
  110.             pWalk->currentLength += segmentLength;
  111.  
  112.         }//end if
  113.                 
  114.         return(stop);
  115.     }
  116.  
  117.  
  118.  
  119. Boolean    ShapeLenToPtCurveto(gxPoint p[3], TShapeLenRec* pWalk);
  120. Boolean    ShapeLenToPtCurveto(gxPoint p[3], TShapeLenRec* pWalk)
  121.     {
  122.         gxCurve        aCurve;
  123.         Boolean        stop = false;        
  124.         double        segmentLength;
  125.  
  126.         aCurve.first.x = p[0].x;
  127.         aCurve.first.y = p[0].y;
  128.         aCurve.control.x = p[1].x;
  129.         aCurve.control.y = p[1].y;
  130.         aCurve.last.x = p[2].x;
  131.         aCurve.last.y = p[2].y;
  132.         
  133.         pWalk->currentPoint.x = p[2].x;
  134.         pWalk->currentPoint.y = p[2].y;
  135.                 
  136.         if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour)  ) {
  137.         
  138.             segmentLength = GetCurveLength(&aCurve);
  139.             
  140.             /* if we've exceeded the desired length, then we're on the correct segment */
  141.             
  142.             if (pWalk->currentLength + segmentLength >= pWalk->desiredLength) {
  143.             
  144.                 /* find the point on this segment that is the length we want */
  145.                                 
  146.                 CurveLengthToPoint(pWalk->desiredLength - pWalk->currentLength, &aCurve, &(pWalk->location), &(pWalk->tangent) );
  147.                 
  148.                 stop = true;
  149.             
  150.             }//end if
  151.         
  152.             pWalk->currentLength += segmentLength;
  153.  
  154.         }//end if
  155.  
  156.         return(stop);
  157.     }
  158.  
  159.  
  160.  
  161. Boolean ShapeLenToPtClosepath( TShapeLenRec* pWalk);
  162. Boolean ShapeLenToPtClosepath( TShapeLenRec* pWalk)
  163.     {
  164.         Boolean            stop = false;
  165.         gxLine            aLine;
  166.         double            segmentLength;
  167.         
  168.         aLine.first.x = pWalk->currentPoint.x;
  169.         aLine.first.y = pWalk->currentPoint.y;
  170.         aLine.last.x = pWalk->firstPoint.x;
  171.         aLine.last.y = pWalk->firstPoint.y;
  172.                 
  173.         pWalk->currentPoint.x = pWalk->firstPoint.x;
  174.         pWalk->currentPoint.y = pWalk->firstPoint.y;
  175.         
  176.         if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour)  ) {
  177.         
  178.             segmentLength = GetLineLength(&aLine);
  179.             
  180.             /* if we've exceeded the desired length, then we're on the correct segment */
  181.             
  182.             if (pWalk->currentLength + segmentLength >= pWalk->desiredLength) {
  183.             
  184.                 /* find the point on this segment that is the length we want */
  185.                 
  186.                 LineLengthToPoint(pWalk->desiredLength - pWalk->currentLength, &aLine, &(pWalk->location), &(pWalk->tangent) );
  187.  
  188.                 stop = true;
  189.             
  190.             }//end if
  191.         
  192.             pWalk->currentLength += segmentLength;
  193.  
  194.         }//end if
  195.  
  196.         return(stop);
  197.     }
  198.  
  199.  
  200.  
  201.  
  202. /*****************************************
  203.  
  204.     Routine: AccurateShapeLengthToPoint.
  205.     
  206.     Replacement for GXShapeLengthToPoint.
  207.     
  208. ******************************************/
  209.  
  210. gxPoint* AccurateShapeLengthToPoint(gxShape target, long index, Fixed length, gxPoint *location, gxPoint *tangent)
  211.     {
  212.         Boolean                    stoppedEarly;    
  213.         TShapeLenRec        shapeLenRec;
  214.         gxPoint                    *result;
  215.         
  216.         result = location;
  217.  
  218.         /* initialize the structure that maintains our state. */
  219.         
  220.         shapeLenRec.currentContour = 0;
  221.         shapeLenRec.desiredContour = index;
  222.         shapeLenRec.currentLength = 0.0;
  223.         shapeLenRec.desiredLength = FixedToDouble(length);
  224.  
  225.         /* Now walk the shape using our shape length calculation callbacks. */
  226.                 
  227.         stoppedEarly = ShapeWalker(target, ShapeLenToPtMoveto, ShapeLenToPtLineto, ShapeLenToPtCurveto, ShapeLenToPtClosepath, &shapeLenRec);
  228.  
  229.         /* if we didn't stop early, then the walker got to the end of the shape without finding the answer */
  230.         
  231.         if (stoppedEarly) {
  232.  
  233.             if (location) {
  234.                 location->x = shapeLenRec.location.x;
  235.                 location->y = shapeLenRec.location.y;
  236.             }
  237.             
  238.             if (tangent) {
  239.                 tangent->x = shapeLenRec.tangent.x;
  240.                 tangent->y = shapeLenRec.tangent.y;
  241.             }        
  242.         
  243.         } else {
  244.         
  245.             GXPostGraphicsError(length_out_of_range);
  246.             
  247.         }//end if
  248.  
  249.         return(result);
  250.     
  251.     }//AccurateShapeLengthToPoint
  252.  
  253.  
  254.  
  255.  
  256. /****** callback Routines for computing total length of the shape *****/
  257.  
  258. Boolean    ShapeLenMoveto(gxPoint *p, TShapeLenRec* pWalk);
  259. Boolean    ShapeLenMoveto(gxPoint *p, TShapeLenRec* pWalk)
  260.     {
  261.  
  262.         pWalk->currentPoint.x = p->x;
  263.         pWalk->currentPoint.y = p->y;
  264.         pWalk->firstPoint.x = p->x;
  265.         pWalk->firstPoint.y = p->y;
  266.  
  267.         pWalk->currentContour += 1;
  268.  
  269.         /* if we've passed the desired contour, stop early */
  270.                 
  271.         if ( (pWalk->desiredContour != 0 ) && (pWalk->currentContour > pWalk->desiredContour) )
  272.             return(true);
  273.         else                
  274.             return(false);
  275.     }
  276.  
  277.  
  278.  
  279. Boolean    ShapeLenLineto(gxPoint *p, TShapeLenRec* pWalk);
  280. Boolean    ShapeLenLineto(gxPoint *p, TShapeLenRec* pWalk)
  281.     {
  282.         gxLine            aLine;
  283.         double            segmentLength;
  284.  
  285.         aLine.first.x = pWalk->currentPoint.x;
  286.         aLine.first.y = pWalk->currentPoint.y;
  287.         aLine.last.x = p->x;
  288.         aLine.last.y = p->y;
  289.         
  290.         pWalk->currentPoint.x = p->x;
  291.         pWalk->currentPoint.y = p->y;
  292.                 
  293.         if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour)  ) {
  294.         
  295.             segmentLength = GetLineLength(&aLine);
  296.                         
  297.             pWalk->currentLength += segmentLength;
  298.                                     
  299.         }//end if
  300.                 
  301.         return(false);
  302.     }
  303.  
  304.  
  305.  
  306. Boolean    ShapeLenCurveto(gxPoint p[3], TShapeLenRec* pWalk);
  307. Boolean    ShapeLenCurveto(gxPoint p[3], TShapeLenRec* pWalk)
  308.     {
  309.         gxCurve        aCurve;
  310.         double        segmentLength;
  311.  
  312.         aCurve.first.x = p[0].x;
  313.         aCurve.first.y = p[0].y;
  314.         aCurve.control.x = p[1].x;
  315.         aCurve.control.y = p[1].y;
  316.         aCurve.last.x = p[2].x;
  317.         aCurve.last.y = p[2].y;
  318.         
  319.         pWalk->currentPoint.x = p[2].x;
  320.         pWalk->currentPoint.y = p[2].y;
  321.                 
  322.         if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour)  ) {
  323.         
  324.             segmentLength = GetCurveLength(&aCurve);
  325.             
  326.             pWalk->currentLength += segmentLength;
  327.                                     
  328.         }//end if
  329.  
  330.         return(false);
  331.     }
  332.  
  333.  
  334.  
  335. Boolean ShapeLenClosepath( TShapeLenRec* pWalk);
  336. Boolean ShapeLenClosepath( TShapeLenRec* pWalk)
  337.     {
  338.         gxLine            aLine;
  339.         double            segmentLength;
  340.         
  341.         aLine.first.x = pWalk->currentPoint.x;
  342.         aLine.first.y = pWalk->currentPoint.y;
  343.         aLine.last.x = pWalk->firstPoint.x;
  344.         aLine.last.y = pWalk->firstPoint.y;
  345.                 
  346.         pWalk->currentPoint.x = pWalk->firstPoint.x;
  347.         pWalk->currentPoint.y = pWalk->firstPoint.y;
  348.         
  349.         if ( (pWalk->desiredContour == 0) || (pWalk->currentContour == pWalk->desiredContour)  ) {
  350.         
  351.             segmentLength = GetLineLength(&aLine);
  352.                         
  353.             pWalk->currentLength += segmentLength;
  354.                                     
  355.         }//end if
  356.  
  357.         return(false);
  358.     }
  359.  
  360.  
  361.  
  362.  
  363.  
  364. /*****************************************
  365.  
  366.     Routine: AccurateGetShapeLength.
  367.     
  368.     Replacement for GXGetShapeLength.
  369.     
  370. ******************************************/
  371.  
  372. wide* AccurateGetShapeLength(gxShape target, long index, wide *wideLength)
  373.     {
  374.         Boolean                    stoppedEarly;    
  375.         TShapeLenRec        shapeLenRec;
  376.         wide                        *result = wideLength;
  377.         
  378.         /* initialize the structure that maintains our state. */
  379.         
  380.         shapeLenRec.currentContour = 0;
  381.         shapeLenRec.desiredContour = index;
  382.         shapeLenRec.currentLength = 0.0;
  383.  
  384.         /* Now walk the shape using our shape length calculation callbacks. */
  385.                 
  386.         stoppedEarly = ShapeWalker(target, ShapeLenMoveto, ShapeLenLineto, ShapeLenCurveto, ShapeLenClosepath, &shapeLenRec);
  387.             
  388.         /* Make a wide number out of the resulting length which is a double */
  389.  
  390.         if ( (shapeLenRec.currentLength < 32767.9999) && (shapeLenRec.currentLength > -32768.9999)) {
  391.         
  392.             double            loPart, hiPart;
  393.  
  394.             loPart = shapeLenRec.currentLength;
  395.             
  396.             // sign extend the lo part into the high part.
  397.             if (loPart > 0)
  398.                 hiPart = 0.0;
  399.             else
  400.                 hiPart = -1.0;
  401.         
  402.             result->lo = DoubleToFixed(loPart);
  403.             result->hi = (long)hiPart;
  404.             
  405.         } else { 
  406.         
  407.             DebugStr("\pI don't know how to convert a big number to a wide ");
  408.             
  409.         }//end if
  410.         
  411.  
  412.         return(result);
  413.     
  414.     }//AccurateGetShapeLength
  415.  
  416.